import requests
import os
from bs4 import BeautifulSoup
from urllib.parse import urljoin
from time import sleep


def download_book_images():
    # 配置参数
    BASE_URL = 'https://books.toscrape.com/'
    SAVE_DIR = '/Users/quanzhi/PycharmProjects/Crawled_Images'
    HEADERS = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
        "Referer": BASE_URL
    }

    try:
        os.makedirs(SAVE_DIR, exist_ok=True)

        # 分页爬取（共50页）
        for page in range(1, 51):
            print(f"\n📖 正在处理第 {page}/50 页")

            try:
                # 构建分页URL
                page_url = urljoin(BASE_URL, f"catalogue/page-{page}.html") if page > 1 else urljoin(BASE_URL, "catalogue/page-1.html")

                # 请求页面（添加重试机制）
                response = requests.get(page_url, headers=HEADERS, timeout=15)
                response.raise_for_status()

                # 解析页面
                soup = BeautifulSoup(response.text, 'html.parser')

                # 获取所有图片容器
                book_items = soup.select('ol.row li.col-xs-6')
                if not book_items:
                    print(f"⚠️ 第 {page} 页未找到图书列表")
                    continue

                # 遍历每本图书
                for index, book in enumerate(book_items, 1):
                    try:
                        # 获取图片信息
                        img_container = book.find('div', class_='image_container')
                        if not img_container:
                            continue

                        a_tag = img_container.find('a')
                        img_tag = a_tag.find('img') if a_tag else None

                        if not img_tag or not img_tag.get('src'):
                            continue

                        # 处理图片元数据
                        alt_text = img_tag.get('alt', f'book_{page}_{index}').strip()
                        src = img_tag['src']

                        # 拼接完整URL（使用当前页面URL作为基准）
                        full_img_url = urljoin(page_url, src)

                        # 生成安全文件名
                        safe_name = "".join(
                            c if c.isalnum() or c in (' ', '-') else '_'
                            for c in alt_text
                        )[:50].strip()  # 限制长度

                        # 跳过空文件名
                        if not safe_name:
                            safe_name = f"book_{page}_{index}"

                        save_path = os.path.join(SAVE_DIR, f"{safe_name}.jpg")

                        # 检查文件是否已存在
                        if os.path.exists(save_path):
                            print(f"⏩ 已跳过: {safe_name}")
                            continue

                        # 下载图片
                        print(f"⬇️ 正在下载: {safe_name}")
                        img_response = requests.get(full_img_url,
                                                    headers=HEADERS,
                                                    stream=True,
                                                    timeout=20)
                        img_response.raise_for_status()

                        # 验证图片类型
                        if 'image' not in img_response.headers.get('Content-Type', ''):
                            print(f"⚠️ 非图片内容: {safe_name}")
                            continue

                        # 保存文件
                        with open(save_path, 'wb') as f:
                            for chunk in img_response.iter_content(chunk_size=8192):
                                if chunk:
                                    f.write(chunk)

                        print(f"✅ 成功保存: {safe_name}")
                        sleep(0.8)  # 礼貌性延迟

                    except requests.exceptions.RequestException as e:
                        print(f"❌ 下载失败 [{safe_name}]: {str(e)}")
                    except Exception as e:
                        print(f"⚠️ 处理失败 [{page}-{index}]: {str(e)}")

                print(f"✔️ 第 {page} 页处理完成")
                sleep(1.5)  # 页间延迟

            except requests.exceptions.RequestException as e:
                print(f"🔴 页面请求失败 [第 {page} 页]: {str(e)}")
                continue

    except KeyboardInterrupt:
        print("\n🛑 用户中断操作")
    except Exception as e:
        print(f"🔥 全局错误: {str(e)}")
    finally:
        print("\n=================================")
        print(f"📂 所有图片已保存到: {SAVE_DIR}")
        print("=================================")


if __name__ == '__main__':
    download_book_images()